use anyhow::Context;
use tracing::{Level, event, info};

pub mod config;
pub mod db;
pub mod model;
pub mod server;
pub mod sync;
pub mod utils;

fn print_help() {
    println!("华为应用市场数据采集工具 v{}", env!("CARGO_PKG_VERSION"));
    println!();
    println!("用法: get_market [选项]");
    println!();
    println!("选项:");
    println!("  -h, --help            显示帮助信息");
    println!("  -v                    启用 DEBUG 级别日志");
    println!("  -vv                   启用 TRACE 级别日志");
    println!("  -d                    启用 WARN 级别日志 (减少输出)");
    println!();
    println!("同步控制:");
    println!("  --no-sync             禁用同步 (应用同步和专题同步)");
    println!("  --no-app-sync         禁用应用同步 (保留专题同步)");
    println!("  --no-db-sync          禁用从数据库获取包名列表");
    println!("  --no-substance-sync   禁用专题(substance)同步");
}

fn main() -> anyhow::Result<()> {
    // 检查是否请求帮助
    let args: Vec<String> = std::env::args().collect();
    if args.contains(&"-h".to_string()) || args.contains(&"--help".to_string()) {
        print_help();
        return Ok(());
    }

    utils::init_log();
    let rt = tokio::runtime::Builder::new_multi_thread()
        .worker_threads(16)
        .enable_all()
        .build()
        .with_context(|| "无法创建 tokio runtime")?;
    event!(Level::INFO, "async rt built");
    rt.block_on(async_main())
}

async fn async_main() -> anyhow::Result<()> {
    // 加载配置
    let _config = config::Config::load().with_context(|| "无法加载配置文件")?;
    let (worker_send, worker_recv) = tokio::sync::oneshot::channel::<()>();

    let worker = tokio::spawn(server::worker(worker_recv));

    // 等待 ctrl + c
    tokio::signal::ctrl_c().await?;

    info!("收到退出信号，正在优雅关闭...");

    // 发送关闭信号
    let _ = worker_send.send(());

    // 等待 worker 完成清理
    match tokio::time::timeout(std::time::Duration::from_secs(10), worker).await {
        Ok(Ok(Ok(()))) => {
            info!("Worker 已优雅退出");
        }
        Ok(Ok(Err(e))) => {
            event!(Level::WARN, "Worker 退出时出错: {:?}", e);
        }
        Ok(Err(e)) => {
            event!(Level::WARN, "Worker 任务失败: {:?}", e);
        }
        Err(_) => {
            event!(Level::WARN, "Worker 退出超时，强制终止");
        }
    }

    Ok(())
}
